Integration Guide Doosan

Note: This integration guide describes the Robot module for an older version of the communication interface (BPS 1.11). The module works with the current Bin Picking Studio (BPS) because of backward compatibility. It does not support features added later (for example, keyed Info data).

Note: We strongly recommend that you read the Robot communication overview before this integration guide.

Contents

1 Prerequisites

The Robot module is compatible with robot controller version GF020500 (2.5.0) and later.

Teach pendant - Screen versions Settings Robot Update

2 Robot controller setup

2.1 Controller configuration

2.1.1 Network configuration

On the teach pendant (TP), open the Setting window from the bottom menu. Then select Network in the list on the left. Configure the static IP address for your network. Make sure that the robot controller and the vision controller are on the same subnet. To confirm the changes, click the Set button.

Teach pendant - settings network

2.2 Robot module installation

The Robot module consists of three core DRL script files in the scripts folder:

  • customer_definitions.txt

  • photoneo_common.txt

  • state_server.txt

Photoneo also provides three bin picking example programs and one semi-automatic calibration example program. They are also DRL scripts and are in the example_programs-scripts folder:

  • main_basic.txt

  • main_multiple_vision_systems.txt

  • main_change_solution.txt

  • main_calibration.txt

You can use these scripts to create your own bin picking tasks, as explained later.

The example_programs-tasks folder contains Task Writer *.tw files. Each file combines the core scripts and one example program script into a complete task. You can run the task after you import it into the TP:

  • BasicExample.tw

  • MultipleVisionSystemsExample.tw

  • ChangeSolutionExample.tw

  • Calibration.tw

  • CalibrationSemiAuto.tw

Note: The CalibrationSemiAuto.tw task contains the semi-automatic calibration example (the DRL script main_calibration.txt). The Calibration.tw task lets you calibrate by hand guiding. For more details about calibration, see this chapter.

2.2.1 Loading the example program

You can use the TP to import the files into the robot controller directly from a USB stick.

To import an example program (a complete task), select Task Writer (for *.tw files) in the bottom menu. In the list on the left, select Import and then click the Search button. A window opens and shows your USB stick. Select it and find your task file. The task opens. To save the task, press the menu icon in the top left corner (☰) and press Save.

The task combines the core DRL scripts and a bin picking example program, which is also a script. For more information on how to run this task, see this chapter.

Teach pendant - tw importing task

2.2.2 Creating a new program from scratch

Each main bin picking program must include the core DRL scripts state_server.txt, photoneo_common.txt, and customer_definitions.txt.

Create a new task in Task Builder or Task Writer (bottom menu). Insert the scripts at the beginning of the MainSub section of the task. To do this, select Command and then select the Custom Code instruction from the list.

Teach pendant - tw add custom script command

Select the new Custom Code instruction and open its Property panel. Then select Import as shown below. A window opens. Select your USB stick and the DRL script file. Press the Confirm button.

Repeat these steps for each core DRL script.

Teach pendant - tw import custom script

Then you can write your own bin picking application.

3 Robot module

The Robot module is designed for easy integration into existing applications.

3.1 Robotic API

Note: We strongly recommend that you read the Photoneo robotic API before this section.

This section describes the API calls of the Robot module. Use these procedures for high-level control of the bin picking application.

3.1.1 Connection procedures

Warning: These procedures are contained in the photoneo_common.txt API section and must not be edited!

Connection procedure

Description / Usage

Connect to Action Request Server

pho_wait_for_server ( server_ip )

Description
Establishes a new connection to the Action Request Server.

Input parameters:

server_ip - string with the IP address of the Action Request Server (Robot interface)

Usage
Call the procedure only once, at the beginning of the program. You can send requests only after the connection is established.
pho_wait_for_server('')

3.1.2 Communication procedures

Note: For a detailed description of these procedures, see Action Requests.

Warning: These procedures are contained in the photoneo_common.txt API section and must not be edited!

Note: In procedures with the optional parameter wait_time, the default value is -1. This means that the timeout for receiving packets is infinite.

Bin picking requests

Request

Input variables

Output variables

Initialization request

pho_request_init
(
pho_start_bin_picking_pose,
pho_end_bin_picking_pose,
vision_system_id,
wait_time = -1
)

pho_start_bin_picking_pose - start joint pose

pho_end_bin_picking_pose - end joint pose

vision_system_id - vision system ID

wait_time - timeout for receiving the response [optional parameter - the default value is infinity]

Note: The pose is a posj object or a list of float values that define the joint angles in degrees.

pho_err_code - error code [global variable]

Scan request

pho_request_scan
(
vision_system_id
)

vision_system_id - vision system ID

Note: The Wait for scan completion procedure receives the response.

Trajectory request

pho_request_trajectory
(
vision_system_id
)

vision_system_id - vision system ID

Note: The Receive trajectory procedure receives the response.

Pick-failed request

pho_request_send_pick_failed
(
vision_system_id
)

vision_system_id - vision system ID

pho_err_code - error code [global variable]

Change scene state request

pho_request_change_env_state
(
state_id
)

state_id - scene state ID

pho_err_code - error code [global variable]

Calibration requests

Request

Input variables

Output variables

Add calibration point request

pho_request_calib_add_point
(
)

—

pho_err_code - error code [global variable]

Solution requests

Request

Input variables

Output variables

Change solution request

pho_request_change_solution
(
required_solution_id
)

required_solution_id - solution ID

pho_err_code - error code [global variable]

Start solution request

pho_request_start_solution
(
required_solution_id
)

required_solution_id - solution ID

pho_err_code - error code [global variable]

Stop solution request

pho_request_stop_solution
(
)

—

pho_err_code - error code [global variable]

Get running solution request

pho_request_get_running_
solution
(
)

—

pho_err_code - error code [global variable]

pho_running_solution - solution ID [global variable]

Get available solutions request

pho_request_get_available_
solutions
(
)

—

pho_err_code - error code [global variable]

pho_available_solutions - array of available solution IDs; the first ID is at index 0 [global variable]

Response receiving procedures

Response receiving procedures

Input variables

Output variables

Wait for scan completion

pho_wait_for_scan_completion
(
wait_time = -1
)

wait_time - timeout for receiving the response [optional parameter - the default value is infinity]

pho_err_code - error code [global variable]

Receive trajectory

pho_receive_trajectory
(
wait_time = -1
)

wait_time - timeout for receiving the response [optional parameter - the default value is infinity]

pho_err_code - error code [global variable]

pho_tool_point_invariance - tool point invariance [global variable]

pho_gripping_point_id - gripping point ID [global variable]

pho_gripping_point_invariance - gripping point invariance [global variable]

3.1.3 Bin picking procedures

Note: These procedures are in the customer_definitions.txt API section. Implement (edit) them as your application requires.

Bin picking procedure

Description / Usage

Gripper attach

gripper_attach
(
)
Description
A user-defined procedure. Typically, it is the attach procedure for grasping the picked object in the Grasp waypoint.
Usage
It runs automatically when the robot reaches a grasping method waypoint that is configured to run the Attach procedure.

Gripper detach

gripper_detach
(
)
Description
A user-defined procedure. Typically, it is the detach procedure for releasing the picked object in the placing routine that the robot operator defines.
Usage
It runs automatically when the robot reaches a grasping method waypoint that is configured to run the Detach procedure.

Note: Typically, this procedure is not configured to run automatically in a waypoint. It is called during placing, which the robot operator implements.

Gripper user-defined 1

gripper_user_1
(
)
Description
A user-defined procedure.
Usage
It runs automatically when the robot reaches a grasping method waypoint that is configured to run the User 1 procedure.

Gripper user-defined 2

gripper_user_2
(
)
Description
A user-defined procedure.
Usage
It runs automatically when the robot reaches a grasping method waypoint that is configured to run the User 2 procedure.

Gripper user-defined 3

gripper_user_3
(
)
Description
A user-defined procedure.
Usage
It runs automatically when the robot reaches a grasping method waypoint that is configured to run the User 3 procedure.

Execute bin picking routine

pho_bin_picking
(
)
Description
Predefined procedure that runs the bin picking routine. You must not edit this procedure directly. To adapt the execution settings, see Bin picking routine execution settings.
Usage
Run it after the bin picking trajectory is received. The robot must be in the start pose when the procedure starts. At the end of the procedure, the robot is in the end pose with the picked object attached to the gripper.

Warning: If you use multiple start poses (different for each vision system), make sure that the robot is in the correct one before you run this procedure.

Set bin picking settings

binpicking_settings
(
)
Description
Predefined procedure that configures the parameters of the individual trajectory segments of the bin picking routine.
Usage
It is called automatically before the bin picking routine runs.

Note: For more about bin picking routine configuration, see Bin picking routine execution settings.

3.2 Example programs

This section contains basic example programs. Each program is for a specific bin picking application and shows the correct use of the robotic API.

These templates also contain simple error handling. It is only an example. You must define your own routines for error situations.

3.2.1 Basic bin picking example

This program is a very basic example of a simple bin picking application. It connects to the vision controller and initializes one vision system. Then, in a loop, it requests a scan and a trajectory, and executes the received trajectory.

Name: main_basic.txt (DRL script in the example_programs-scripts folder, used in the BasicExample.tw task in the example_programs-tasks folder)

# BasicExample module v.1.7
# Copyright(c) 2023 Photoneo s.r.o.
# All rights reserved


# Adjust Vision Controller IP address if necessary
BINPICKING_SRV_IP = ''

# Definition of global variables (proper values are set in the main function)
home_pose = None
start_pose = None
end_pose = None

MAX_ERR_COUNT = 2
err_counter = 0


def main_binpicking_example_basic():
    global pho_err_code, pho_err_occurred, err_counter, BINPICKING_SRV_IP,  home_pose, start_pose, end_pose

    # Start the state server in a separate thread
    pho_start_state_server()

    # Reset state of error handling variables
    err_counter = 0
    pho_err_code = PhoCommErr.OK


    # Note that: Instead of the poses definitions below you may also
    # use joint pose variables defined in the task (in properties of task commands: GlobalVariables / Define),
    # where you can adjust the values more easily when working with teach pendant

    # Reteach home position for your application
    home_pose = posj(167.0, -27.0, -101.0, 178.0, 48.0, -16.0)

    # Reteach bin picking start and end pose
    start_pose = posj(167.0, -38.0, -101.0, 178.0, 48.0, -16.0)
    end_pose = posj(150.0, -38.0, -101.0, 178.0, 48.0, -16.0)

    # Set Vision System ID (default = 1)
    vision_system_id = 1

    # Connect to the Vision Controller,
    if not pho_wait_for_server(BINPICKING_SRV_IP):
        exit()

    # Send bin picking initialization request for the current Vision System ID,
    # start & end poses sent via this request will be used in trajectory planning pipeline
    pho_request_init(start_pose, end_pose, vision_system_id)

    # Move the robot out of the scanning volume!
    movej(home_pose, v=50, a=150)

    # Request first scan
    pho_request_scan(vision_system_id)

    while True:
        # ==================== PHOTONEO BIN PICKING START ====================
        # Wait for scan completion
        pho_wait_for_scan_completion()

        # Handle errors if occurred
        if pho_err_occurred:
            err_handling(vision_system_id)
            continue  # start the loop again

        # Request trajectory
        pho_request_trajectory(vision_system_id)

        # Move to start position while the trajectory is being calculated
        movej(start_pose, v=50, a=200)

        # Receive trajectory (sequence of operations & operations data)
        pho_receive_trajectory()

        # Execute bin picking application if the trajectory was received with no error
        if not pho_err_occurred:
            pho_bin_picking()
        # ==================== PHOTONEO BIN PICKING END ====================

        if pho_err_occurred:
            err_handling(vision_system_id)
            continue
        else:
            # Clear error counter
            err_counter = 0

            # ==================== PLACING START ====================
            # Move the robot away so that we can trigger a new scan
            # movej(home_pose, v=50, a=150)

            # Trigger next scan, so that
            # localization and trajectory computation for the next cycle can run while the object is being placed
            pho_request_scan(vision_system_id)

            # Commands for actual part placing (reteach position for your robot and work cell)
            # movej(posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0), v=50, a=100)
            # gripper_detach()
            # movej(home_pose, v=50, a=150)
            # ==================== PLACING END ====================


def err_handling(vision_system_id):
    global pho_err_occurred, pho_err_code, MAX_ERR_COUNT, err_counter, \
        home_pose, start_pose, end_pose, BINPICKING_SRV_IP

    # Release the gripper if necessary
    # gripper_detach()

    # Move robot to home pose
    movej(home_pose, v=50, a=150)

    # Log the error
    err_code_str = '"{}" ({})'.format(
        PhoCommErrND.get(pho_err_code, PhoBipiErrND.get(pho_err_code, '?')),
        pho_err_code)
    tp_log('Error occurred: {}'.format(err_code_str))

    if err_counter >= MAX_ERR_COUNT:
        # Log error & exit (exits via the popup window)
        tp_popup('Photoneo internal error: {}. '
                 'Please reboot the Vision Controller and restart application'.format(err_code_str),
                 DR_PM_ALARM, 1)

    # If planning failed or no part was found, notify user and continue by a new scan request (Adjust if necessary)
    if pho_err_code in [PhoBipiErr.PLANNING_FAILED, PhoBipiErr.NO_PART_FOUND]:
        tp_log('No part found or path planning failed')
        pho_request_scan(vision_system_id)

    # If bin picking has not been initialized or service returned error response,
    # reinitialize and send a new scan request (Adjust if necessary)
    elif pho_err_code == PhoBipiErr.NOT_INITIALIZED:
        wait(5.0)
        pho_request_init(start_pose, end_pose, vision_system_id)
        pho_request_scan(vision_system_id)

    # if bin picking returned error response, reinitialize and trigger a new scan (Adjust if necessary)
    elif pho_err_code == PhoCommErr.SERVICE_ERR:
        wait(10.0)
        pho_request_init(start_pose, end_pose, vision_system_id)
        pho_request_scan(vision_system_id)

    # In case of communication failure, log the error and exit program
    elif pho_err_code in [PhoCommErr.BAD_DATA, PhoCommErr.TIMEOUT, PhoCommErr.COMM_FAILURE]:
        wait(10.0)
        pho_wait_for_server(BINPICKING_SRV_IP)
        pho_request_init(start_pose, end_pose, vision_system_id)
        pho_request_scan(vision_system_id)

    # Otherwise trigger next scan and try to continue
    else:
        pho_request_scan(vision_system_id)

    err_counter += 1

    # Clear the error flag
    pho_err_occurred = False

main_binpicking_example_basic()

3.2.2 Multiple Vision Systems example

This program extends the basic bin picking example. It initializes two vision systems instead of one and switches between them in each cycle.

Name: main_multiple_vision_systems.txt (DRL script in the example_programs-scripts folder, used in the MultipleVisionSystemsExample.tw task in the example_programs-tasks folder)

# MultipleVisionSystemExample module v.1.7
# Copyright(c) 2023 Photoneo s.r.o.
# All rights reserved


# Adjust Vision Controller IP address if necessary
BINPICKING_SRV_IP = ''

# Definition of global variables (proper values are set in the main function)
home_pose = None
start_pose = None
end_pose = None

MAX_ERR_COUNT = 5
err_counter = 0


def main_multiple_vision_systems_example():
    global pho_err_code, pho_err_occurred, err_counter, BINPICKING_SRV_IP, home_pose, start_pose, end_pose

    # Start the state server in a separate thread
    pho_start_state_server()

    # Reset state of error handling variables
    err_counter = 0
    pho_err_code = PhoCommErr.OK

    # Set Vision System ID (default = 1)
    vision_system_ids = [1, 2]
    active_vision_system_id = vision_system_ids[0]


    # Note that: Instead of the poses definitions below you may also
    # use joint pose variables defined in the task (in properties of task commands: GlobalVariables / Define),
    # where you can adjust the values more easily when working with teach pendant
    # An example code of using GlobalVariables from a task is commented below
    # or you may use the provided task MultipleVisionSyxtemsExample.tw which has poses defined in GlobalVariables

    # Reteach home pose, bin picking start and end pose for your application
    # home_pose = Global_home_pose
    # start_pose = {vision_system_ids[0]: Global_start_pose_1,
    #               vision_system_ids[1]: Global_start_pose_2}
    # end_pose = {vision_system_ids[0]: Global_end_pose_1,
    #             vision_system_ids[1]: Global_end_pose_2}

    # Reteach home pose, bin picking start and end pose for your application
    # In case you're using poses defined in the task from above, remove/comment pose definitions below
    start_pose = {vision_system_ids[0]: posj(3.29, -34.42, 130.6, -6.62, 58.61, -68.77),
                  vision_system_ids[1]: posj(12.21, -34.42, 130.6, -6.62, 58.61, -68.77)}
    end_pose = {vision_system_ids[0]: posj(43.59, 30.48, 92.73, -2.61, 53.47, -73.04),
                vision_system_ids[1]: posj(43.59, 30.48, 92.73, -2.61, 53.47, -73.04)}
    home_pose = posj(8.29, -34.42, 130.6, -6.62, 58.61, -68.77)

    # Connect to the Vision Controller,
    if not pho_wait_for_server(BINPICKING_SRV_IP):
        exit()

    # Send bin picking initialization request for the current Vision System ID,
    # start & end poses sent via this request will be used in trajectory planning pipeline
    pho_request_init(start_pose[vision_system_ids[0]], end_pose[vision_system_ids[0]], vision_system_ids[0])
    pho_request_init(start_pose[vision_system_ids[1]], end_pose[vision_system_ids[1]], vision_system_ids[1])

    # Move the robot out of the scanning volume!
    movej(home_pose, v=50, a=150)

    # Request first scan
    pho_request_scan(active_vision_system_id)

    while True:
        # ==================== PHOTONEO BIN PICKING START ====================
        # Wait for scan completion
        pho_wait_for_scan_completion()

        # Handle errors if occurred
        if pho_err_occurred:
            err_handling(active_vision_system_id)
            continue  # start the loop again

        # Request trajectory
        pho_request_trajectory(active_vision_system_id)

        # Move to start position while the trajectory is being calculated
        movej(start_pose[active_vision_system_id], v=50, a=200)

        # Receive trajectory (sequence of operations & operations data)
        pho_receive_trajectory()

        # Execute bin picking application if the trajectory was received with no error
        if not pho_err_occurred:
            pho_bin_picking()
        # ==================== PHOTONEO BIN PICKING END ====================

        if pho_err_occurred:
            err_handling(active_vision_system_id)
            continue
        else:
            # Clear error counter
            err_counter = 0

            # ==================== PLACING START ====================
            # Move the robot away so that we can trigger a new scan
            # movej(home_pose, v=50, a=150)

            # Switch active vision system
            if active_vision_system_id == vision_system_ids[0]:
                active_vision_system_id = vision_system_ids[1]
            else:
                active_vision_system_id = vision_system_ids[0]

            # Trigger next scan, so that
            # localization and trajectory computation for the next cycle can run while the object is being placed
            pho_request_scan(active_vision_system_id)

            # Commands for actual part placing (reteach position for your robot and work cell)
            # movej(posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0), v=50, a=100)
            # gripper_detach()
            # movej(home_pose, v=50, a=150)
            # ==================== PLACING END ====================


def err_handling(vision_system_id):
    global pho_err_occurred, pho_err_code, MAX_ERR_COUNT, err_counter, \
        home_pose, start_pose, end_pose, BINPICKING_SRV_IP

    # Release the gripper if necessary
    # gripper_detach()

    # Move robot to home pose
    movej(home_pose, v=50, a=150)

    # Log the error
    err_code_str = '"{}" ({})'.format(
        PhoCommErrND.get(pho_err_code, PhoBipiErrND.get(pho_err_code, '?')),
        pho_err_code)
    tp_log('Error occurred: {}'.format(err_code_str))

    if err_counter >= MAX_ERR_COUNT:
        # Log error & exit (exits via the popup window)
        tp_popup('Photoneo internal error: {}. '
                 'Please reboot the Vision Controller and restart application'.format(err_code_str),
                 DR_PM_ALARM, 1)

    # If planning failed or no part was found, notify user and continue by a new scan request (Adjust if necessary)
    if pho_err_code in [PhoBipiErr.PLANNING_FAILED, PhoBipiErr.NO_PART_FOUND]:
        tp_log('No part found or path planning failed')
        pho_request_scan(vision_system_id)

    # If bin picking has not been initialized or service returned error response,
    # reinitialize and send a new scan request (Adjust if necessary)
    elif pho_err_code == PhoBipiErr.NOT_INITIALIZED:
        wait(5.0)
        pho_request_init(start_pose[vision_system_id], end_pose[vision_system_id], vision_system_id)
        pho_request_scan(vision_system_id)

    # if bin picking returned error response, reinitialize and trigger a new scan (Adjust if necessary)
    elif pho_err_code == PhoCommErr.SERVICE_ERR:
        wait(10.0)
        pho_request_init(start_pose[vision_system_id], end_pose[vision_system_id], vision_system_id)
        pho_request_scan(vision_system_id)

    # In case of communication failure, log the error and exit program
    elif pho_err_code in [PhoCommErr.BAD_DATA, PhoCommErr.TIMEOUT, PhoCommErr.COMM_FAILURE]:
        wait(10.0)
        pho_wait_for_server(BINPICKING_SRV_IP)
        pho_request_init(start_pose[vision_system_id], end_pose[vision_system_id], vision_system_id)
        pho_request_scan(vision_system_id)



    # Otherwise trigger next scan and try to continue
    else:
        pho_request_scan(vision_system_id)

    err_counter += 1

    # Clear the error flag
    pho_err_occurred = False

main_multiple_vision_systems_example()

3.2.3 Change solution example

One robotic cell can take part in several production processes. To handle multiple parts at the same time, use multiple vision systems in one solution. If you change the production process completely, it is better to have separate solutions. The robot can deploy them directly.

This program extends the basic bin picking example. After a defined number of bin picking cycles, it sends a request to change the deployed solution.

Name: main_change_solution.txt (DRL script in the example_programs-scripts folder, used in the ChangeSolutionExample.tw task in the example_programs-tasks folder)

# SolutionExample module v.1.7
# Copyright(c) 2023 Photoneo s.r.o.
# All rights reserved


# Adjust Vision Controller IP address if necessary
BINPICKING_SRV_IP = ''

# Definition of global variables (proper values are set in the main function)
home_pose = None
start_pose = None
end_pose = None

MAX_ERR_COUNT = 2
err_counter = 0

CHANGE_SOLUTION_AFTER_PICK_COUNT = 5Name: main_change_solution.txt (DRL script located in folder example_programs-scripts, used in task ChangeSolutionExample.tw located in folder example_programs-tasks)
EXIT_AFTER_SOLUTION_CHANGE = True


def main_solution_example():
    global pho_err_code, pho_err_occurred, err_counter, BINPICKING_SRV_IP,  home_pose, start_pose, end_pose, \
        pho_available_solutions, pho_running_solution

    # Start the state server in a separate thread
    pho_start_state_server()

    # Reset state of error handling variables
    err_counter = 0
    pho_err_code = PhoCommErr.OK

    pick_counter = 0

    solution_id_1 = 1
    solution_id_2 = 2
    actual_solution = solution_id_2


    # Note that: Instead of the poses definitions below you may also
    # use joint pose variables defined in the task (in properties of task commands: GlobalVariables / Define),
    # where you can adjust the values more easily when working with teach pendant

    # Reteach home position for your application
    home_pose = posj(167.0, -27.0, -101.0, 178.0, 48.0, -16.0)

    # Reteach bin picking start and end pose
    start_pose = posj(167.0, -38.0, -101.0, 178.0, 48.0, -16.0)
    end_pose = posj(150.0, -38.0, -101.0, 178.0, 48.0, -16.0)

    # Set Vision System ID (default = 1)
    vision_system_id = 1

    # Connect to the Vision Controller,
    if not pho_wait_for_server(BINPICKING_SRV_IP):
        exit()

    # Get available solutions
    pho_request_get_available_solutions()
    tp_log('Available solution/solutions is/are: {}'.format(pho_available_solutions))

    # Start solution 1
    pho_request_start_solution(solution_id_2)

    # Get running solution
    pho_request_get_running_solution()
    tp_log('Currently is running solution with ID: {}'.format(pho_running_solution))

    # Send bin picking initialization request for the current Vision System ID,
    # start & end poses sent via this request will be used in trajectory planning pipeline
    pho_request_init(start_pose, end_pose, vision_system_id)

    # Move the robot out of the scanning volume!
    movej(home_pose, v=50, a=150)

    # Request first scan
    pho_request_scan(vision_system_id)

    while True:
        # ==================== PHOTONEO BIN PICKING START ====================
        # Wait for scan completion
        pho_wait_for_scan_completion(5.0)

        # Handle errors if occurred
        if pho_err_occurred:
            err_handling(vision_system_id, actual_solution)
            continue  # start the loop again

        # Request trajectory
        pho_request_trajectory(vision_system_id)

        # Move to start position while the trajectory is being calculated
        movej(start_pose, v=50, a=200)

        # Receive trajectory (sequence of operations & operations data)
        pho_receive_trajectory()

        # Execute bin picking application if the trajectory was received with no error
        if not pho_err_occurred:
            pho_bin_picking()
        # ==================== PHOTONEO BIN PICKING END ====================

        if pho_err_occurred:
            err_handling(vision_system_id, actual_solution)
            continue
        else:
            # Clear error counter
            err_counter = 0

            # Increment pick counter
            pick_counter += 1

            # ==================== PLACING START ====================
            # Move the robot away so that we can trigger a new scan
            # movej(home_pose, v=50, a=150)

            # Do not request scan in case the solution switch will follow after placing the part
            if pick_counter < CHANGE_SOLUTION_AFTER_PICK_COUNT:
                # Trigger next scan, so that
                # localization and trajectory computation for the next cycle can run while the object is being placed
                pho_request_scan(vision_system_id)

            # Commands for actual part placing (reteach position for your robot and work cell)
            # movej(posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0), v=50, a=100)
            # gripper_detach()
            # movej(home_pose, v=50, a=150)
            # ==================== PLACING END ====================

        # If required number of picked parts is reached, call change solution request and production will be changed
        if pick_counter >= CHANGE_SOLUTION_AFTER_PICK_COUNT:

            pick_counter = 0
            if actual_solution == solution_id_1:
                actual_solution = solution_id_2
            else:
                actual_solution = solution_id_1

            # ==================== CHANGING OF PRODUCTION START ====================
            # Move the robot to home position
            movej(home_pose, v=50, a=150)
            pho_request_change_solution(actual_solution)

            # Get running solution
            pho_request_get_running_solution()
            tp_log('Currently is running solution with ID: {}'.format(pho_running_solution))

            pho_wait_for_server(BINPICKING_SRV_IP)
            pho_request_init(start_pose, end_pose, vision_system_id)

            # Wait 10 sec to see that solution was changed
            wait(15.0)
            if EXIT_AFTER_SOLUTION_CHANGE:
                pho_request_stop_solution()
                exit()
            else:
                pho_request_scan(vision_system_id)
            # ==================== CHANGING OF PRODUCTION END ====================


def err_handling(vision_system_id, solution_id):
    global pho_err_occurred, pho_err_code, MAX_ERR_COUNT, err_counter, \
        home_pose, start_pose, end_pose, BINPICKING_SRV_IP

    # Release the gripper if necessary
    # gripper_detach()

    # Move robot to home pose
    movej(home_pose, v=50, a=150)

    # Log the error
    err_code_str = '"{}" ({})'.format(
        PhoCommErrND.get(pho_err_code, PhoBipiErrND.get(pho_err_code, '?')),
        pho_err_code)
    tp_log('Error occurred: {} (solution ID: {}; Vision System ID: {})'.format(
        err_code_str, solution_id, vision_system_id))

    if err_counter >= MAX_ERR_COUNT:
        # Log error & exit (exits via the popup window)
        tp_popup('Photoneo internal error: {}. '
                 'Please reboot the Vision Controller and restart application'.format(err_code_str),
                 DR_PM_ALARM, 1)

    # If planning failed or no part was found, notify user and continue by a new scan request (Adjust if necessary)
    if pho_err_code in [PhoBipiErr.PLANNING_FAILED, PhoBipiErr.NO_PART_FOUND]:
        tp_log('No part found or path planning failed')
        pho_request_scan(vision_system_id)

    # If bin picking has not been initialized or service returned error response,
    # reinitialize and send a new scan request (Adjust if necessary)
    elif pho_err_code == PhoBipiErr.NOT_INITIALIZED:
        wait(5.0)
        pho_request_init(start_pose, end_pose, vision_system_id)
        pho_request_scan(vision_system_id)

    # if bin picking returned error response, reinitialize and trigger a new scan (Adjust if necessary)
    elif pho_err_code == PhoCommErr.SERVICE_ERR:
        wait(10.0)
        pho_request_init(start_pose, end_pose, vision_system_id)
        pho_request_scan(vision_system_id)

    # In case of communication failure, log the error and exit program
    elif pho_err_code in [PhoCommErr.BAD_DATA, PhoCommErr.TIMEOUT, PhoCommErr.COMM_FAILURE]:
        wait(10.0)
        pho_wait_for_server(BINPICKING_SRV_IP)
        pho_request_init(start_pose, end_pose, vision_system_id)
        pho_request_scan(vision_system_id)

    # Otherwise trigger next scan and try to continue
    else:
        pho_request_scan(vision_system_id)

    err_counter += 1

    # Clear the error flag
    pho_err_occurred = False

main_solution_example()

3.2.4 Calibration example

This program is a template for semi-automatic calibration.

Before you run the program:

  • Teach the calibration home pose. The robot moves through this pose to each calibration pose.

  • Teach the calibration poses.

  • Start the calibration in BPS.

Now you can start the program. The robot moves to each calibration pose and sends the Add calibration point request when it reaches the pose. Between the calibration poses, the robot moves through the calibration home pose. When all calibration points are added, the program ends. If you are satisfied with the calibration result, save it in BPS.

Name: main_calibration.txt (DRL script in the example_programs-scripts folder, used in the CalibrationSemiAuto.tw task in the example_programs-tasks folder)

# CalibrationExample module v.1.7
# Copyright(c) 2023 Photoneo s.r.o.
# All rights reserved


# Adjust Vision Controller IP address if necessary
BINPICKING_SRV_IP = ''

# Definition of global variables (proper values are set in the main function)
home_pose = None

MAX_ERR_COUNT = 2
err_counter = 0

# calibration_positions should be uncommented and adjusted according to the scene
# calibration_positions = [
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
#    posj(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
# ]


def main_calibration_example():
    global pho_err_code, pho_err_occurred, err_counter, BINPICKING_SRV_IP,  home_pose

    # Start the state server in a separate thread
    pho_start_state_server()

    # Reset state of error handling variables
    err_counter = 0
    pho_err_code = PhoCommErr.OK


    # Note that: Instead of the poses definitions below you may also
    # use joint pose variables defined in the task (in properties of task commands: GlobalVariables / Define),
    # where you can adjust the values more easily when working with teach pendant

    # Reteach home position for your application
    home_pose = posj(167.0, -27.0, -101.0, 178.0, 48.0, -16.0)

    # Connect to the Vision Controller,
    if not pho_wait_for_server(BINPICKING_SRV_IP):
        exit()

    # Move the robot out of the scanning volume!
    movej(home_pose, v=50, a=150)

    for calibration_pose in calibration_positions:

        # Move robot to one of the calibration position
        movej(calibration_pose, v=50, a=150)

        # Request for add calibration point
        pho_request_calib_add_point()

        movej(home_pose, v=50, a=150)

        # Check if the error occurred. If there is error the error code is logged to robot logs and the calibration is stopped
        if pho_err_occurred:
            tp_log('An error has occurred when calibration point was added. The error code is: {} '.format(pho_err_code))
            break


main_calibration_example()

3.3 Error handling

If an error occurs while the requested operation runs, the global error flag (pho_error_occurred) is set to true. The error code is stored in the global variable pho_err_code. We recommend that you add suitable error handling for your application after each synchronous request and response receiving procedure.

For the list of error codes with descriptions and troubleshooting, see here.

The most important error codes are defined as constants in the DRL script photoneo_common.txt. They are split into two classes with static variables:

class PhoCommErr

Error code

DRL constant

No error (0)

OK = 0

Service error (1)

SERVICE_ERR = 1

Communication error (3)

COMM_FAILURE = 3

Bad data (4)

BAD_DATA = 4

Timeout (5)

TIMEOUT = 5


class PhoBipiErr

Error code

DRL constant

Path planning failed (201)

PLANNING_FAILED = 201

No object found (202)

NO_PART_FOUND = 202

Vision system not initialized (203)

NOT_INITIALIZED = 203

Empty scene (218)

EMPTY_SCENE = 218

Wrong bin picking configuration (255)

WRONG_BP_CONF = 255


Note: Example programs provide basic error handling.

4 Running the basic bin picking example program

4.1 Prerequisites

Before you can run the Basic bin picking example, make sure that:

  • A fully configured BPS solution with a single vision system is ready for deployment.

  • The robot controller is configured as described in Robot controller setup.

  • The BPS network settings are configured.

  • The gripper procedures are implemented (optional - without them, the robot does not actually pick the object).

  • The placing procedure is implemented.

4.2 Bin picking routine execution settings

The DRL script customer_definitions.txt contains the procedure Set bin picking settings (binpicking_settings). Use it to set the speeds of the individual trajectories of the bin picking routine.
The procedure sets the speed and acceleration values in the arrays pho_speed_data and pho_acceleration_data. These values are always set before the bin picking routine runs.

By default, the speeds and accelerations of the first 6 trajectories of the bin picking routine are configured. (The default number of trajectories in a bin picking routine is 4, as defined in the grasping method of the BPS solution.)

For each trajectory, you can define one float value [degrees per second] as the speed for all joints. Or you can define a list of 6 float values as the speeds for the individual joints. The same applies to the acceleration data [degrees per second^2].

Adapt these values to your requirements. If you add custom path stages (trajectories), configure the matching number of values in the pho_speed_data and pho_acceleration_data arrays. Keep the order of the trajectories: the first value (list of 6 values) in the array applies to the first trajectory, the second value (list of 6 values) to the second trajectory, and so on.

By default, the procedure sets maximum speeds for all joints and an acceleration of 400 deg/s^2.
The procedure defines the list max_velocity, which contains the maximum speed for each joint (each joint has a different maximum speed). The speeds also differ between robot models. If you want to use the list max_velocity, adapt these values to your robot model. For example, for the Doosan M1013:
max_velocity = [120.0, 120.0, 180.0, 225.0, 225.0, 225.0]

The list of acceleration values per joint is defined as follows (the same value for all 6 joints):

acceleration = [400] * 6

The speeds and accelerations for a trajectory segment are then added to the arrays pho_speed_data and pho_acceleration_data:

pho_speed_data.append([maxvj * 1.0 for maxvj in max_velocity])
pho_acceleration_data.append(acceleration)

4.3 Reteach the robot poses

An important step of the bin picking configuration is to teach the home, start, and end poses. Teach the home position so that the robot is outside the scanning area. Teach the start position so that the robot gripper is approximately above the center of the bin. The end position can be similar to the start position or slightly shifted towards the placing area. Do not define the end pose too far from the bin. This can affect path planning (longer total planning time, planning errors, and so on).

The basic bin picking example program uses the following poses:

home_pose - Home position, a posj object, for example:

home_pose = posj(167.0, -27.0, -101.0, 178.0, 48.0, -16.0)

start_pose - Start position, a posj object or a list of float values defining the joint angles in degrees

end_pose - End position, a posj object or a list of float values defining the joint angles in degrees

You can also define the poses as joint pose variables in the task (in the properties of the task commands: GlobalVariables / Define). This makes it easier to adjust the values on the teach pendant. For example:

home_pose = Global_home_pose

4.4 Runtime

Deploy your BPS solution. On the Deployment page in BPS, the Action Request Client status should be DISCONNECTED (from the Action Request Server).

Before you run a task, start the servo. To do this, open the Status screen and press On. Then close the screen with ‘X’ in the top left corner, as shown below.

Teach pendant - status screen jogging 1

When the servo is on, select the task that you want to run. If the correct task is already open (the task name is shown in the top left corner), press the Run button (option A in the image below).

To select a different task, press the Menu button (☰), select Open, and select the task (option B in the images below).

Teach pendant - main menu
Teach pendant - main menu open 2
Teach pendant - running task

On the Deployment page, the Action Request Client status and the Robot State Server status change to CONNECTED.

The robot now starts to send requests to the vision controller and to execute bin picking movements.

Note: Be ready to stop the robot motion immediately. We strongly recommend that you reduce the speed to 10% of maximum during the first bin picking tests.

4.5 Logging

The Photoneo robotic API uses the function tp_log(). These logs have the default category Log Message, which is not shown while the task runs. Only the most important messages are shown, in a popup window. These are usually fatal errors that stop the task. To see all logged messages from the task, open Settings > Log Message on the TP.

Teach pendant - settings logs

5 Migration guide

This chapter describes how to update your Robot module to a newer version.

5.1 Robot module update

Follow these steps to update your current Robot module to a newer version that is compatible with your BPS version:

  1. Back up your changes in the script customer_definitions.txt. It contains your custom settings and the gripper action procedures.

  2. Remove the scripts that you loaded into your main task: photoneo_common.txt, customer_definitions.txt, and state_server.txt.

  3. Load the new version of these scripts into your main task.

  4. Apply your changes from the old customer_definitions.txt to the new one.

  5. Read the API changes in the new version of the Robot module carefully. If necessary, update the API calls in your main program.

6 Calibration

During calibration, the Robot State Server must run to provide the current state of the robot. The Robot State Server also provides data for hand-eye bin picking and for real-time visualization of the robot. The main Robot State Server functions are in the DRL script state_server.txt. It also needs definitions from photoneo_common.txt. The procedure pho_start_state_server() starts the Robot State Server. It creates a server socket and runs in a separate thread. When a client connects, the server starts to send the robot state data. If the client disconnects, the server waits for a new client.

Because of this, each task must include the script state_server.txt (and photoneo_common.txt) and start the server with this call:

pho_start_state_server()

6.1 Hand guiding

The task Calibration.tw contains the scripts needed to run the Robot State Server. It calls the procedure that starts the server and then starts hand guiding. Before you start the calibration task, make sure that a collaborative zone is enabled. The zone must be large enough for you to jog the robot through all the space needed for calibration. The task does not and cannot check whether the collaborative zone is enabled! If the zone is not enabled, a green light is shown on link 6 and you cannot move the robot. If the collaborative zone is set and the current robot pose is inside the zone, a blue light is shown. This means that you can jog the robot manually while you hold the hand-guide button on the robot cockpit or on the TP. An example of a collaborative zone setting is shown below.

Teach pendant - collaborative zone

6.2 Semi-automatic

The DRL script main_calibration.txt is a template for semi-automatic calibration. Import it into a task together with the scripts state_server.txt and photoneo_common.txt. Or use the task CalibrationSemiAuto.tw, which already includes the calibration template and the required scripts.
The DRL script main_calibration.txt starts the Robot State Server and connects to the Action Request Server. Then it moves the robot through predefined calibration poses. In each pose, the robot itself requests a new calibration point. You must teach these poses before you run the task.

The operator only needs to start the calibration in BPS and finish it (check the result and save it).